package dungeonElements;

import org.junit.*;
import static org.junit.Assert.*;

import temperature.Temperature;
import dungeonTools.Direction;

/**
 * @author Tom Jacobs & Ewoud De Moor
 * @version 3.0
 */
public class BorderTest {

	public static Square square;
	
	@Before
	public void setUp() throws Exception {
		square = new NormalSquare();
	}
	
	@After
	public void tearDown() throws Exception {
	}
	
	
	//Square:
	@Test (expected = IllegalArgumentException.class)
	public void newSquareException_invalidBorders(){
		Square newSquare = new NormalSquare(Temperature.CELSIUS_0, 3.00d, false, false, false, false, false, false);
		assertEquals(true, newSquare.hasProperBorders());
	}
	
	@Test 
	public void newSquare_validBorders(){
		Square newSquare = new NormalSquare(Temperature.CELSIUS_0, 3.00d, false, false, false, false, false, true);
		assertEquals(true, newSquare.hasProperBorders());
		Square newSquare2 = new NormalSquare(Temperature.CELSIUS_0, 3.00d, true, false, false, false, false, false);
		assertEquals(true, newSquare2.hasProperBorders());
		Square newSquare3 = new NormalSquare(Temperature.CELSIUS_0, 3.00d, false, false, true, false, false, false);
		assertEquals(true, newSquare3.hasProperBorders());
		Square newSquare4 = new NormalSquare(Temperature.CELSIUS_0, 3.00d, false, true, false, true, true, false);
		assertEquals(true, newSquare4.hasProperBorders());
	}
	
	@Test 
	public void newSquare_validBorders_allBorders(){
		Square newSquare = new NormalSquare(Temperature.CELSIUS_0, 3.00d, true, true, true, true, true, true);
		assertEquals(true, newSquare.hasProperBorders());
	}
	
	@Test 
	public void canHaveAsBorderInDirection_terminatedBorder(){
		Border border = square.getBorder(Direction.SOUTH);
		border.terminate();
		assertEquals(false, square.canHaveAsBorderInDirection(border, Direction.SOUTH));
	}
	
	@Test 
	public void breakBorder_valid(){
		for( Direction testDirection : Direction.values() ){
			if(testDirection!=Direction.NORTH){
				Border border = square.getBorder(testDirection);
				assertEquals(true,border.hasSquareInDirection(testDirection.getOppositeDirection()));
				square.breakBorder(testDirection);
				assertEquals(false, border.hasSquareInDirection(testDirection.getOppositeDirection()));
				assertEquals(true, border.hasProperBorderingSquares());
				assertEquals(false, square.hasBorderInDirection(testDirection));
				assertNull( square.getBorder(testDirection));
				assertEquals(true, square.hasProperBorders());
			}
		}
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void breakBorderException_allBorders(){
		for(Direction testDirection : Direction.values() ){
			square.breakBorder(testDirection);
		}
	}
	
	@Test 
	public void buildWall_valid(){
		for(Direction testDirection : Direction.values() ){
			Border formerBorder = square.getBorder(testDirection);
			if(testDirection==Direction.NORTH)
				square.breakBorder(testDirection);
			square.buildWall(testDirection);
			assertEquals(true, square.getBorder(testDirection) instanceof Wall);
			assertEquals(square, square.getBorder(testDirection).getSquareInDirection(testDirection.getOppositeDirection()));
			assertEquals(false, formerBorder.hasSquareInDirection(testDirection.getOppositeDirection()));
			assertEquals(true, formerBorder.isTerminated());
		}
	}
	
	@Test 
	public void buildWall_withSharedBorders(){
		for(Direction testDirection : Direction.values() ){
			Border border = square.getBorder(testDirection);
			Square newSquare = new NormalSquare();
			newSquare.setBorder(border, testDirection.getOppositeDirection());
			if(testDirection==Direction.NORTH)
				square.breakBorder(testDirection);
			square.buildWall(testDirection);
			assertEquals(true, square.getBorder(testDirection) instanceof Wall);
			assertEquals(square, square.getBorder(testDirection).getSquareInDirection(testDirection.getOppositeDirection()));
			assertEquals(false, border.hasSquareInDirection(testDirection.getOppositeDirection()));
		}
	}
	
	@Test 
	public void buildDoor_valid(){
		Border formerBorder1 = square.getBorder(Direction.EAST);
		square.buildDoor(Direction.EAST);
		assertEquals(true, square.getBorder(Direction.EAST) instanceof Door);
		assertEquals(square, square.getBorder(Direction.EAST).getSquareInDirection(Direction.EAST.getOppositeDirection()));
		assertEquals(false, formerBorder1.hasSquareInDirection(Direction.EAST.getOppositeDirection()));
		
		Border formerBorder2 = square.getBorder(Direction.WEST);
		square.buildDoor(Direction.WEST);
		assertEquals(true, square.getBorder(Direction.WEST) instanceof Door);
		assertEquals(square, square.getBorder(Direction.WEST).getSquareInDirection(Direction.WEST.getOppositeDirection()));
		assertEquals(false, formerBorder2.hasSquareInDirection(Direction.WEST.getOppositeDirection()));
		
		Border formerBorder3 = square.getBorder(Direction.CEILING);
		square.buildDoor(Direction.CEILING);
		assertEquals(true, square.getBorder(Direction.CEILING) instanceof Door);
		assertEquals(square, square.getBorder(Direction.CEILING).getSquareInDirection(Direction.CEILING.getOppositeDirection()));
		assertEquals(false, formerBorder3.hasSquareInDirection(Direction.CEILING.getOppositeDirection()));
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void buildDoorException_doorInFloor(){
		square.buildDoor(Direction.FLOOR);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void buildDoorException_fourDoors(){
		for(Direction testDirection : Direction.values() ){
			if( (testDirection!=Direction.FLOOR) && (testDirection!=Direction.NORTH) )
				square.buildDoor(testDirection);
		}
	}
	
	//Border:
	@Test 
	public void terminateBorder_valid(){
		for(Direction testDirection : Direction.values() ){
			if(testDirection!=Direction.NORTH){
				Border border = square.getBorder(testDirection);
				border.terminate();
				assertEquals(true, border.isTerminated());
				for(Direction direction : Direction.values() ){
					assertEquals(false, border.hasSquareInDirection(direction));
				}
				assertEquals(false, square.hasBorderInDirection(testDirection));
				assertNull( square.getBorder(testDirection));
				assertEquals(true, square.hasProperBorders());
			}
		}
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void terminateBorderExeption_terminateBordersInAllDirections(){
		for(Direction testDirection : Direction.values() ){
			Border border = square.getBorder(testDirection);
			border.terminate();
			assertEquals(true, border.isTerminated());
			for(Direction direction : Direction.values() ){
				assertEquals(false, border.hasSquareInDirection(direction));
			}
			assertEquals(false, square.hasBorderInDirection(testDirection));
			assertNull( square.getBorder(testDirection));
		}
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void getSquareInDirection_invalidDirection(){
		square.getBorder(Direction.NORTH).getSquareInDirection(Direction.CEILING);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void getSquareInDirection_invalidDirection_null(){
		square.getBorder(Direction.NORTH).getSquareInDirection(null);
	}
	
	@Test 
	public void canHaveAsSquareInDirection_conflictingDirection(){
		Border border = square.getBorder(Direction.NORTH);
		Square newSquare = new NormalSquare();
		for(Direction testDirection : Direction.values() ){
			if( (testDirection!=Direction.NORTH)&&(testDirection!=Direction.NORTH.getOppositeDirection())) 
				assertEquals(false,border.canHaveAsSquareInDirection(newSquare, Direction.FLOOR));
		}
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void setSquareInDirectionException_twoSquaresInSameDirection(){
		Border border = square.getBorder(Direction.FLOOR);
		Square otherSquare = new NormalSquare();
		otherSquare.setBorder(border, Direction.FLOOR);
	}
	
	@Test 
	public void setSquareInDirection_valid(){
		Border border = square.getBorder(Direction.WEST);
		Square newSquare = new NormalSquare();
		border.setSquareInDirection(newSquare, Direction.WEST);
		assertEquals( border,newSquare.getBorder(Direction.EAST) );
		assertEquals(newSquare,border.getSquareInDirection(Direction.WEST));
		assertEquals( border,square.getBorder(Direction.WEST) );
		assertEquals(square,border.getSquareInDirection(Direction.EAST));
	}
	
	//Wall:
	@Test 
	public void hasSlipperySurface(){
		square.setSlipperySurface(false);
		square.breakBorder(Direction.WEST);
		square.buildWall(Direction.WEST);
		Border border = square.getBorder(Direction.WEST);
		assertFalse( ((Wall) border).hasSlipperySurface() );
		square.setSlipperySurface(true);
		square.breakBorder(Direction.WEST);
		square.buildWall(Direction.WEST);
		Border border2 = square.getBorder(Direction.WEST);
		assertTrue( ((Wall) border2).hasSlipperySurface() );
	}
	
	//Door:
	@Test 
	public void openClosedDoor(){
		square.buildDoor(Direction.EAST);
		Door door = (Door)square.getBorder(Direction.EAST);
		assertTrue( door.isClosed() );
		door.openDoor();
		assertFalse( door.isClosed() );
	}
		
		@Test 
		public void closeOpenDoor(){
			square.buildDoor(Direction.EAST);
			Door door = (Door)square.getBorder(Direction.EAST);
			door.openDoor();
			assertFalse( door.isClosed() );
			door.closeDoor();
			assertTrue( door.isClosed() );
	}
		
}
